﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;
using System.Drawing;
using System.Runtime.InteropServices;
using System.IO;

namespace SanjaySingh.DefaultBrowserPackage
{
    /// <summary>
    /// URL Association types
    /// </summary>
    public enum URLAssociationType
    {
        http,
        https
    }
    /// <summary>
    /// Represents a browser on this machine
    /// </summary>
    public class Browser : IDisposable
    {
        #region Private Members

        private const string InstalledBrowserRegistrationLocationForx64MachinesKey = @"SOFTWARE\WOW6432Node\Clients\StartMenuInternet";
        private const string InstalledBrowserRegistrationLocationForx32MachinesKey = @"SOFTWARE\Clients\StartMenuInternet";
        private const string BrowserExeLocationKey = @"shell\open\command";
        private const string DefaultIconKey = "DefaultIcon";
        private const string URLAssociationKeyFormat = @"Software\Microsoft\Windows\Shell\Associations\UrlAssociations\{0}\UserChoice";
        private Dictionary<URLAssociationType, string> urlAssociations = new Dictionary<URLAssociationType, string>();
        
        #endregion

        #region Constructors

        /// <summary>
        /// Prevents a default instance of the <see cref="Browser"/> class from being created.
        /// </summary>
        private Browser(string name, string executablePath)
        {
            this.Name = name;
            this.ExecutablePath = executablePath;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets a value indicating whether this instance is internet explorer.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is internet explorer; otherwise, <c>false</c>.
        /// </value>
        public bool IsInternetExplorer
        {
            get
            {
                return this.Name.ToLower().Contains("internet explorer");
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is chrome.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance is chrome; otherwise, <c>false</c>.
        /// </value>
        public bool IsChrome
        {
            get
            {
                return this.Name.ToLower().Contains("chrome");
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is firefox.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is firefox; otherwise, <c>false</c>.
        /// </value>
        public bool IsFirefox
        {
            get
            {
                return this.Name.ToLower().Contains("firefox");
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is safari.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance is safari; otherwise, <c>false</c>.
        /// </value>
        public bool IsSafari
        {
            get
            {
                return this.Name.ToLower().Contains("safari");
            }
        }
        
        /// <summary>
        /// Gets the name.
        /// </summary>
        public string Name
        {
            get;
            private set;
        }


       
        /// <summary>
        /// Gets the executable path.
        /// </summary>
        public string ExecutablePath
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets a value indicating whether this instance is default.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is default; otherwise, <c>false</c>.
        /// </value>
        public bool IsDefault
        {
            get
            {
                return this.CheckIfIsDefault(); ;
            }
        }
        #endregion

        #region Public Methods

       
        /// <summary>
        /// Makes the default for visual studio.
        /// </summary>
        public void MakeDefaultForVisualStudio()
        {
            //Update registry for setting default browser
            foreach (var urlAssociationKeyValue in urlAssociations)
            {
                using (var currAssocationRegKey = Registry.CurrentUser.OpenSubKey(string.Format(URLAssociationKeyFormat, urlAssociationKeyValue.Key), true))
                {
                    currAssocationRegKey.SetValue("Progid", urlAssociationKeyValue.Value);
                }
            }
            string browserFile = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Microsoft\VisualStudio\10.0"), "browsers.xml");

            try
            {
                if (File.Exists(browserFile))
                {
                    File.Delete(browserFile);
                }
            }
            catch
            {

            }
        }

        /// <summary>
        /// Gets all installed browsers.
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Browser> GetAllInstalledBrowsers()
        {
            List<Browser> installedBrowsers = new List<Browser>();
            using (RegistryKey browserKeys = Registry.LocalMachine.OpenSubKey(InstalledBrowserRegistrationLocationForx64MachinesKey) ?? Registry.LocalMachine.OpenSubKey(InstalledBrowserRegistrationLocationForx32MachinesKey))
            {
                foreach (var browserEntryName in browserKeys.GetSubKeyNames())
                {
                    using (RegistryKey browserKey = browserKeys.OpenSubKey(browserEntryName))
                    {
                        
                        // read executablepath
                        string executablePath = string.Empty;
                        using (var executablePathKey = browserKey.OpenSubKey(BrowserExeLocationKey))
                        {
                            executablePath = (string)executablePathKey.GetValue(null);
                        }

                        var browser = new Browser((string)browserKey.GetValue(null),  executablePath);

                        // extract url associations
                        var capabilityKey = browserKey.OpenSubKey("Capabilities");
                        if (capabilityKey != null)
                        {
                            using (var urlAssociationKey = capabilityKey.OpenSubKey("URLAssociations"))
                            {
                                foreach (string associationTypeKey in Enum.GetNames(typeof(URLAssociationType)))
                                {
                                    browser.urlAssociations.Add((URLAssociationType)Enum.Parse(typeof(URLAssociationType), associationTypeKey), (string)urlAssociationKey.GetValue(associationTypeKey));
                                }
                            }
                            capabilityKey.Dispose();
                        }
                        else if (browser.IsInternetExplorer)
                        {
                            browser.urlAssociations.Add(URLAssociationType.http, "IE.HTTP");
                            browser.urlAssociations.Add(URLAssociationType.https, "IE.HTTPS");
                        }
                        
                        installedBrowsers.Add(browser);
                    }
                }
            }
            
            
            return installedBrowsers;
        }

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            

        }

        #endregion

        #region Private Methods

        private bool CheckIfIsDefault()
        {
            foreach (var urlAssociationKeyValue in urlAssociations)
            {
                using (var currAssocationRegKey = Registry.CurrentUser.OpenSubKey(string.Format(URLAssociationKeyFormat, urlAssociationKeyValue.Key), true))
                {
                    if (currAssocationRegKey != null)
                    {
                        string progID = currAssocationRegKey.GetValue("Progid", string.Empty).ToString();
                        return progID == urlAssociationKeyValue.Value;
                    }
                }
            }
            return false;
        }

        #endregion
    }
}
